﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace mevsukovGames
{

    public enum Direction
    {
        Left = 0,
        Right = 1,
        Down = 2,
        Rotate = 3

    }
    class TetrisLogic
    {
        private int _xStartPoint;
        private int _yStartPoint;
        private int _gameFieldHeight;
        private int _gameFieldWidth;
        private int _delay;
        private InputHandlerBase _inputHandler;
        private GameField _field;
        private CoordinateCalculator _calc;
        private ShapeGenerator _sg;
        private ConsoleRenderer _cr;
        private int _step;
        private int _score;
        private int _scoreModifier;
        private SoundPlayer _player;

        public TetrisLogic(InputHandlerBase inputHandler, int xStartPoint, int yStartPoint, int gameFieldHeight, int gameFieldWidth, int step, int delay,SoundPlayer player) //5,5, 20, 10)
        {
            _inputHandler = inputHandler;
            _xStartPoint = xStartPoint;
            _yStartPoint = yStartPoint;
            _gameFieldHeight = gameFieldHeight;
            _gameFieldWidth = gameFieldWidth;
            _field = new GameField(gameFieldWidth, gameFieldHeight);
            _cr = new ConsoleRenderer(xStartPoint, yStartPoint);
            _calc = new CoordinateCalculator(xStartPoint, yStartPoint, gameFieldWidth, gameFieldHeight);
            _sg = new ShapeGenerator(gameFieldWidth/2-1, 0);
            _step = step;
            _delay = delay;
            _score = 0;
            _player = player;
        }

        void _inputHandler_MoveRight(object sender, EventArgs e)
        {
            if (IsNextPositionFree(_sg.ShapeStack[0], Direction.Right))
            {
                _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                _sg.ShapeStack[0].MoveRight(_step);
                _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
            }
        }

        void _inputHandler_MoveLeft(object sender, EventArgs e)
        {
            if (IsNextPositionFree(_sg.ShapeStack[0], Direction.Left))
            {
                _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                _sg.ShapeStack[0].MoveLeft(_step);
                _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
            }
        }

        void _inputHandler_MoveDown(object sender, EventArgs e)
        {
            if(IsNextPositionFree(_sg.ShapeStack[0], Direction.Down))
            {
                _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                _sg.ShapeStack[0].MoveDown(_step);
                _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
            }
        }

        void _inputHandler_Rotate(object sender, EventArgs e)
        {
            _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
            _sg.ShapeStack[0].RotateShape();
            if (!IsNextPositionFree(_sg.ShapeStack[0], Direction.Rotate))
            {
                _sg.ShapeStack[0].RotateShape();
                _sg.ShapeStack[0].RotateShape();
                _sg.ShapeStack[0].RotateShape();
            }
            _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
        }

        public void StartGame()
        {
            _inputHandler.MoveLeft += _inputHandler_MoveLeft;
            _inputHandler.MoveRight +=_inputHandler_MoveRight;
            _inputHandler.MoveDown +=_inputHandler_MoveDown;
            _inputHandler.Rotate +=_inputHandler_Rotate;

            if (_player != null)
                _player.StartMusic();

            int xShift = _gameFieldWidth + 2;
            int yShift = 3;
            _cr.RenderFrames(_field);
            _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
            _cr.RenderNextShape(_sg.ShapeStack[1], xShift, yShift, _calc);
            _cr.RenderScore(_score, xShift, yShift, _calc);
            _cr.RenderGameField(_field, _calc);
            bool flag = true;
            while (flag)
            {
                _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                _inputHandler.QueryKeyBoard();
                if (IsNextPositionFree(_sg.ShapeStack[0], Direction.Down))
                {
                    _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                    _sg.ShapeStack[0].MoveDown(_step);
                    _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
                }
                else
                {
                    _cr.ClearFieldShape(_sg.ShapeStack[0], _field, _calc);
                    if (_field.AddShape(_sg.ShapeStack[0]))
                    {
                        CalculateScore(_field.ClearLines());
                        SetupSpeed(50);
                        _cr.RenderScore(_score, xShift, yShift, _calc);
                        _cr.RenderGameField(_field, _calc);
                        _cr.ClearNextShape(_sg.ShapeStack[1], xShift, yShift, _calc);
                        _sg.AddNewShape();
                        _cr.RenderNextShape(_sg.ShapeStack[1], xShift, yShift, _calc);
                    }
                    else
                        flag = false;
                }
                _cr.RenderFieldShape(_sg.ShapeStack[0], _field, _calc);
                Thread.Sleep(_delay);
            }

            if (_player != null)
                _player.StopMusic();


            _cr.PrintGameOver();
        }

        public bool IsNextPositionFree(Shape sh, Direction dir)
        {
            switch (dir)
            {
                case Direction.Left:
                    if (!_field.IsPositionFree(sh.FirstBlock.BlockCoordinates.XCoordinate - _step, sh.FirstBlock.BlockCoordinates.YCoordinate,
                        sh.SecondBlock.BlockCoordinates.XCoordinate - _step, sh.SecondBlock.BlockCoordinates.YCoordinate,
                        sh.ThirdBlock.BlockCoordinates.XCoordinate - _step, sh.ThirdBlock.BlockCoordinates.YCoordinate,
                        sh.FourthBlock.BlockCoordinates.XCoordinate - _step, sh.FourthBlock.BlockCoordinates.YCoordinate))
                        return false;
                    else
                        return true;
                case Direction.Right:
                    if (!_field.IsPositionFree(sh.FirstBlock.BlockCoordinates.XCoordinate + _step, sh.FirstBlock.BlockCoordinates.YCoordinate,
                      sh.SecondBlock.BlockCoordinates.XCoordinate + _step, sh.SecondBlock.BlockCoordinates.YCoordinate,
                      sh.ThirdBlock.BlockCoordinates.XCoordinate + _step, sh.ThirdBlock.BlockCoordinates.YCoordinate,
                      sh.FourthBlock.BlockCoordinates.XCoordinate + _step, sh.FourthBlock.BlockCoordinates.YCoordinate))
                        return false;
                    else
                        return true;

                case Direction.Rotate:
                    if (!_field.IsPositionFree(sh.FirstBlock.BlockCoordinates.XCoordinate, sh.FirstBlock.BlockCoordinates.YCoordinate,
                      sh.SecondBlock.BlockCoordinates.XCoordinate, sh.SecondBlock.BlockCoordinates.YCoordinate,
                      sh.ThirdBlock.BlockCoordinates.XCoordinate, sh.ThirdBlock.BlockCoordinates.YCoordinate,
                      sh.FourthBlock.BlockCoordinates.XCoordinate, sh.FourthBlock.BlockCoordinates.YCoordinate))
                        return false;
                    else
                        return true;

                case Direction.Down:
                    if (sh.FirstBlock.BlockCoordinates.YCoordinate + _step > 0 && !_field.IsPositionFree(sh.FirstBlock.BlockCoordinates.XCoordinate, sh.FirstBlock.BlockCoordinates.YCoordinate + _step))
                        return false;
                    else if (sh.SecondBlock.BlockCoordinates.YCoordinate + _step > 0 && !_field.IsPositionFree(sh.SecondBlock.BlockCoordinates.XCoordinate, sh.SecondBlock.BlockCoordinates.YCoordinate + _step))
                        return false;
                    else if (sh.ThirdBlock.BlockCoordinates.YCoordinate + _step > 0 && !_field.IsPositionFree(sh.ThirdBlock.BlockCoordinates.XCoordinate, sh.ThirdBlock.BlockCoordinates.YCoordinate + _step))
                        return false;
                    else if (sh.FourthBlock.BlockCoordinates.YCoordinate + _step > 0 && !_field.IsPositionFree(sh.FourthBlock.BlockCoordinates.XCoordinate, sh.FourthBlock.BlockCoordinates.YCoordinate + _step))
                        return false;
                    else if (sh.FirstBlock.BlockCoordinates.YCoordinate + _step >= _field.Height)
                        return false;
                    return true;
            }
            return false;
        }

        public void CalculateScore(int value)
        {
            switch (value)
            {
                case 1:
                    _score += 100;
                    _scoreModifier += 100;
                    _cr.Beep();
                    break;
                case 2:
                    _score += 300;
                    _scoreModifier += 300;
                    _cr.Beep();
                    break;
                case 3:
                    _score += 700;
                    _scoreModifier += 700;
                    _cr.Beep();
                    break;
                case 4:
                    _score += 1500;
                    _scoreModifier += 1500;
                    _cr.Beep();
                    break;
            }
        }

        public void SetupSpeed(int speedDelay)
        {
            if (_scoreModifier >= 2000)
                if (!(_delay <= speedDelay))
                {
                    _delay -= speedDelay;
                    _scoreModifier = 1000;
                }
            if(_scoreModifier>=1000)
                if (!(_delay <= speedDelay))
                {
                    _delay -= speedDelay;
                    _scoreModifier = 0;
                }
        }

    }
}
